package com.csii.config.esb;

import com.csii.adhoc.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

/**
 * socket链接
 */
@Component
@Slf4j
public class EsbSocketReqUtil {

    /**
     * 报文长度
     */
    private static int MSG_LEN = 8;
    private static int BUFFER_SIZE = 2048;

    @Value("${esb.url}")
    private String esbUrl;

    @Value("${esb.timeout}")
    private String esbTimeout;

    @Value("${esb.port}")
    private String esbPort;

    public String sendRequest(Map<String, String> map, String tranCode) throws Exception {
        String sb = getXmlBody(map);
        String xmlString = getXMLString(tranCode, sb);
        String res = sendRequest(xmlString, "utf-8");
        return res;
    }

    private String getXmlBody(Map<String, String> map) {
        StringBuilder sb = new StringBuilder();
        if (map != null && map.size() != 0) {
            map.forEach((x, y) -> {
                if (y == null){
                    y = "";
                }
                sb.append("<").append(x).append(">").append(y).append("</" + x + ">");
            });
        }
        return sb.toString();
    }

    public String sendRequest(String xmlString, String charset)
            throws Exception {
        String result = null;
        Socket socket = null;
        OutputStream out = null;
        InputStream in = null;

        byte[] tempBuf = new byte[BUFFER_SIZE];
        try {
            socket = new Socket();
            //设置超时时间
            socket.setSoTimeout(Integer.parseInt(esbTimeout));
            socket = new Socket(esbUrl, Integer.parseInt(esbPort));
            log.info("connection successful............");
            in = socket.getInputStream();
            out = socket.getOutputStream();

            // 发送总长度，4个自己长度域 　+　实际发送的字节
            ByteBuffer totalBuf = ByteBuffer.allocate(xmlString.getBytes(charset).length
                    + MSG_LEN);

            // 报文长度
            byte[] lenBuf = String.format("%0" + MSG_LEN + "d",
                    xmlString.getBytes(charset).length).getBytes(charset);
            log.info("报文长度" + xmlString.getBytes(charset).length);
            log.info("lenBuf" + lenBuf.toString());
            totalBuf.put(lenBuf);
            totalBuf.put(xmlString.getBytes(charset));
            out.write(totalBuf.array());
            out.flush();

            // 获取MSG_LEN位报文长度
            lenBuf = new byte[MSG_LEN];
            if ((in.read(lenBuf)) != MSG_LEN) {
                throw new Exception("读取报文长度异常!");
            }
            int len = Integer.parseInt(new String(lenBuf));

            byte[] respBuf = new byte[len];
            int num = 0, realLen = 0;
            while ((num = in.read(tempBuf)) != -1 && (realLen < len)) {
                System.arraycopy(tempBuf, 0, respBuf, realLen, num);
                realLen += num;
            }
            log.info("RECV MSG IS:[" + new String(respBuf, charset) + "]");
            result = new String(respBuf, charset);
        } finally {
            if (null != out) {
                out.close();
            }
            if (null != in) {
                in.close();
            }
            if (null != socket) {
                socket.close();
            }
        }
        return result;
    }

    /**
     * 生成适配远端传输过来的xml文件的string
     *
     * @return
     */
    private String getXMLString(String tranCode, String reqBody) {
        StringBuilder xmlBuffer = new StringBuilder();
        String reqDateTime = DateUtils.getDateString("yyyyMMddHHmmss");
        xmlBuffer.
                append("<root>").
                append("<reqHeader>"). // 请求头

                append("<tranCode>").append(tranCode).append("</tranCode>"). // 交易码
                append("<versionNo>").append("").append("</versionNo>"). // 版本号
                append("<reqGlobalNo>").append("").append("</reqGlobalNo>").// 请求全局流水号
                append("<reqNo>").append("").append("</reqNo>").// 请求系统流水号
                append("<reqBusNo>").append("").append("</reqBusNo>").// 请求系统业务流水号
                append("<reqDateTime>").append(reqDateTime).append("</reqDateTime>").// 请求系统交易日期时间

                append("<reqId>").append("").append("</reqId>").// 请求系统编号 数仓 DWS
                append("<reqChnl>").append("INTERNAL").append("</reqChnl>"). // 请求渠道

                // 这块基本没用到,先写在这里,不输入值
                        append("<instNo>").append("").append("</instNo>").// 机构号
                append("<tradTeller>").append("").append("</tradTeller>").// 操作员号
                append("<termId>").append("").append("</termId>").// 终端号
                append("<busDomain>").append("").append("</busDomain>").// 业务域
                append("<prodNo>").append("").append("</prodNo>"). // 产品编码
                append("<reTeller>").append("").append("</reTeller>").// 复核操作员
                append("<authTeller>").append("").append("</authTeller>").// 授权操作员
                append("<reqUser>").append("").append("</reqUser>").// 请求用户
                append("<reqPwd>").append("").append("</reqPwd>").// 请求密码
                append("<reqSign>").append("").append("</reqSign>").// 请求签名域
                append("<appendInfo>").append("").append("</appendInfo>").// 附加信息
                append("<recNumber>").append("").append("</recNumber>").// 对账编号

                append("</reqHeader>").
                append("<reqBody>").
                append(reqBody).
                append("</reqBody>").
                append("</root>");
        return xmlBuffer.toString();
    }

}
